import 'package:flutter/material.dart';

import '../../types/animate_do_mixins.dart';
import '../../types/animate_do_types.dart';

/// [key]: optional widget key reference
/// [child]: mandatory, widget to animate
/// [duration]: how much time the animation should take
/// [delay]: delay before the animation starts
/// [controller]: optional/mandatory, exposes the animation controller created by Animate_do
/// [manualTrigger]: boolean that indicates if you want to trigger the animation manually with the controller
/// [animate]: For a State controller property, if you re-render changing it from false to true, the animation will be fired immediately
/// [onFinish]: callback that returns the direction of the animation, [AnimateDoDirection.forward] or [AnimateDoDirection.backward]
/// [curve]: curve for the animation
class FadeInUpCont extends StatefulWidget {
  final Widget child;
  final Duration duration;
  final Duration delay;
  final AnimationController controller;
  final bool manualTrigger;
  final bool animate;
  final double from;
  final Function(AnimateDoDirection direction)? onFinish;
  final Curve curve;

  FadeInUpCont(
      {key,
      required this.child,
      this.duration = const Duration(milliseconds: 800),
      this.delay = Duration.zero,
      required this.controller,
      this.manualTrigger = false,
      this.animate = true,
      this.from = 100,
      this.onFinish,
      this.curve = Curves.easeOut})
      : super(key: key) {
    if (manualTrigger == true) {
      throw FlutterError('If you want to use manualTrigger:true, \n\n'
          'Then you must provide the controller property, that is a callback like:\n\n'
          ' ( controller: AnimationController) => yourController = controller \n\n');
    }
  }

  @override
  FadeInUpContState createState() => FadeInUpContState();
}

/// FadeState class
/// The animation magic happens here
class FadeInUpContState extends State<FadeInUpCont> with AnimateDoState {
  /// Animation controller if requested

  /// Animation movement
  late Animation<double> animation;

  /// Animation opacity
  late Animation<double> opacity;

  @override
  void dispose() {
    disposed = true;
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    controller = widget.controller;

    animation = Tween<double>(begin: widget.from, end: 0)
        .animate(CurvedAnimation(parent: controller, curve: widget.curve));
    opacity = Tween<double>(begin: 0, end: 1).animate(
        CurvedAnimation(parent: controller, curve: const Interval(0, 0.65)));

    /// Provided by the mixing [AnimateDoState] class
    configAnimation(
        delay: widget.delay,
        animate: widget.animate,
        manualTrigger: widget.manualTrigger,
        infinite: false,
        onFinish: widget.onFinish);
  }

  @override
  Widget build(BuildContext context) {
    /// Provided by the mixing [AnimateDoState] class
    buildAnimation(
        delay: widget.delay,
        animate: widget.animate,
        manualTrigger: widget.manualTrigger,
        infinite: false,
        onFinish: widget.onFinish);

    return AnimatedBuilder(
        animation: controller,
        child: widget.child,
        builder: (BuildContext context, Widget? child) {
          return Transform.translate(
              offset: Offset(0, animation.value),
              child: Opacity(
                opacity: opacity.value,
                child: child,
              ));
        });
  }
}
